#ifndef _WX_DYNAMICLOADER_H__
#define _WX_DYNAMICLOADER_H__

#include "wx/defs.h"
#include "wx/dynlib.h"
#include "wx/hashmap.h"
#include "wx/module.h"
#include <tr1/unordered_map>

class wxPluginLibrary;

typedef std::tr1::unordered_map< wxString, wxPluginLibrary*, wxStringHash, wxStringEqual > wxDLManifest;
typedef wxDLManifest wxDLImports;

class wxPluginLibrary : public wxDynamicLibrary {
  public:
    static wxDLImports* ms_classes;  // Static hash of all imported classes.
    wxPluginLibrary( const wxString &libname, int flags = wxDL_DEFAULT );
    ~wxPluginLibrary();
    wxPluginLibrary  *RefLib();
    bool              UnrefLib();
    void  RefObj() { ++m_objcount; }
    void  UnrefObj() {
      wxASSERT_MSG( m_objcount > 0, wxT( "Too many objects deleted??" ) );
      --m_objcount;
    }
    bool  IsLoaded() const { return m_linkcount > 0; }
    void  Unload() { UnrefLib(); }
  private:
    wxClassInfo    *m_before;       // sm_first before loading this lib
    wxClassInfo    *m_after;        // ..and after.
    size_t          m_linkcount;    // Ref count of library link calls
    size_t          m_objcount;     // ..and (pluggable) object instantiations.
    wxModuleList    m_wxmodules;    // any wxModules that we initialised.
    void    UpdateClasses();        // Update ms_classes
    void    RestoreClasses();       // Removes this library from ms_classes
    void    RegisterModules();      // Init any wxModules in the lib.
    void    UnregisterModules();    // Cleanup any wxModules we installed.
    DECLARE_NO_COPY_CLASS( wxPluginLibrary )
};

class wxPluginManager {
  public:
    static wxPluginLibrary    *LoadLibrary( const wxString &libname,int flags = wxDL_DEFAULT );
    static bool                UnloadLibrary( const wxString &libname );
    wxPluginManager() : m_entry( NULL ) {}
    wxPluginManager( const wxString &libname, int flags = wxDL_DEFAULT ) {
      Load( libname, flags );
    }
    ~wxPluginManager() { if( IsLoaded() ) Unload(); }
    bool   Load( const wxString &libname, int flags = wxDL_DEFAULT );
    void   Unload();
    bool   IsLoaded() const { return m_entry && m_entry->IsLoaded(); }
    void  *GetSymbol( const wxString &symbol, bool *success = 0 ) {
      return m_entry->GetSymbol( symbol, success );
    }
    static void CreateManifest() { ms_manifest = new wxDLManifest( wxKEY_STRING ); }
    static void ClearManifest() { delete ms_manifest; ms_manifest = NULL; }
  private:
    static wxPluginLibrary *FindByName( const wxString& name ) {
      const wxDLManifest::iterator i = ms_manifest->find( name );
      return i == ms_manifest->end() ? NULL : i->second;
    }
    static wxDLManifest* ms_manifest;  // Static hash of loaded libs.
    wxPluginLibrary*     m_entry;      // Cache our entry in the manifest.
    DECLARE_NO_COPY_CLASS( wxPluginManager )
};

#endif  // _WX_DYNAMICLOADER_H__
